/**
 * 工厂方法模式
 * 定义一个创建对象的接口，其子类去具体现实这个接口以完成具体的创建工作。
 * 如果需要增加新的产品类，只需要扩展一个相应的工厂类即可。
 * 工厂方法模式适合应用场景:
 * 1. 在编写代码的过程中，如果无法预知对象确切类别及其依赖关系时，可使用工厂方法。工厂方法将创建产品的代码与实际使用产品的代码分离，从而能在不影响其他代码的情况下扩展产品创建部分代码。
 * 2. 如果希望用户能扩展软件库或框架的内部组件，可使用工厂方法。将各框架中构造组件的代码集中到单个工厂方法中， 并在继承该组件之外允许任何人对该方法进行重写。
 * 3. 如果希望复用现有对象来节省系统资源，而不是每次都重新创建对象，可使用工厂方法。
 * 缺点：产品类数据较多时，需要实现大量的工厂类，这无疑增加了代码量。
 */
#pragma once

#include <string>
#include <memory>
#include <iostream>

using namespace std;

namespace factorymethod
{
class AbstractSheos
{
public:
    virtual const string color() const = 0;
};

class WhiteSheos : public AbstractSheos
{
public:
    const string color() const override {
        return "White Sheos";
    }
};

class BlackSheos : public AbstractSheos
{
public:
    const string color() const override {
        return "Black Sheos";
    }
};

//工厂方法的基类，定义创建产品接口
class AbstractFactory
{
public:
    virtual AbstractSheos* createSheos() const = 0;
};

class WhiteSheosFactory : public AbstractFactory
{
public:
    AbstractSheos* createSheos() const override {
        return new WhiteSheos();
    }
};

class BlackSheosFactory : public AbstractFactory
{
public:
    AbstractSheos* createSheos() const override {
        return new BlackSheos();
    }
};

void ClientCode(AbstractFactory* factory)
{
    unique_ptr<AbstractSheos> sheos(factory->createSheos());
    cout << "Sheos Color:" << sheos->color() << endl;
}

} // namespace factorymethod